#include <basic_types.h>
#include <mediatypes.h>

#include <api/libc/printf.h>
#include <hld/osd/osddrv.h>
#include <api/libsubt/subt_osd.h>
#include <api/libsubt/lib_subt.h>
//#include "osd_lib.h"
#include <hld/hld_dev.h>
#include <hld/sdec/sdec.h>
#include <hld/dis/vpo.h>

extern struct subt_config_par g_subt_config_par;//
extern struct osd_device *osd_dev;
extern BOOL g_subt_show_on;

#define SUBT_PRINTF	PRINTF

static UINT16 m_TotalHeight = 0;
static struct OSDRect m_SubtRegion[MAX_REGION_IN_PAGE+1];
static BOOL m_UsedRegion_2m[MAX_REGION_IN_PAGE+1];
static BOOL m_ShownRegion[MAX_REGION_IN_PAGE+1];
static UINT16 l_subtosd_sema_id;
static BOOL m_InSubtDecoding = FALSE;

#define ENTER_SUBT_OSD_API()	{m_InSubtDecoding = TRUE;} //{osal_semaphore_capture(l_subtosd_sema_id,TMO_FEVR);} //dont use semaphore, because this function is called in "draw pixel" funcion which can afect performance --Michael 2007/1/26
#define LEAVE_SUBT_OSD_API()	{m_InSubtDecoding = FALSE;} //{osal_semaphore_release(l_subtosd_sema_id);}

static BOOL create_blank_region = FALSE;//cloud

static UINT8 osd_subt_del_region(UINT8 RegionID)
{
    if(m_UsedRegion_2m[RegionID])
    {
        //if(RegionID==0)
        //    libc_printf("delete region %d\n", RegionID);
        OSDDrv_DeleteRegion((HANDLE)osd_dev, RegionID);
        m_UsedRegion_2m[RegionID] = FALSE;
        m_ShownRegion[RegionID] = FALSE;
        m_TotalHeight -= m_SubtRegion[RegionID].uHeight;
    }
    return SUCCESS;
}

BOOL osd_region_is_created_2m(UINT8 region_idx)
{
    ENTER_SUBT_OSD_API();
    if(g_subt_show_on == FALSE)
    {
        LEAVE_SUBT_OSD_API();
		return FALSE;
    }
    region_idx++;
    LEAVE_SUBT_OSD_API();
    return m_UsedRegion_2m[region_idx];
}

__ATTRIBUTE_RAM_
INT32 osd_subt_create_region_2m(UINT8 region_idx, struct OSDRect *pRegion)
{
    UINT8 i;
	
    ENTER_SUBT_OSD_API();
    if(g_subt_show_on == FALSE)
    {
        LEAVE_SUBT_OSD_API();
		return FALSE;
    }
    if(create_blank_region!=TRUE)
        region_idx++;

    //if(region_idx==0)
    //    libc_printf("create region %d\n", region_idx);
    //libc_printf("%s: uLeft = %d, uTop = %d, uWidth = %d, uHeight= %d\n", \
    //    __FUNCTION__, pRegion->uLeft, pRegion->uTop, pRegion->uWidth, pRegion->uHeight);

    
    // delete overlap region
    for(i = 1; i < MAX_REGION_IN_PAGE; i++)
    {

        if(m_UsedRegion_2m[i])
        {
            if(m_SubtRegion[i].uTop+m_SubtRegion[i].uHeight-1 >= pRegion->uTop)
            {
                 if(m_SubtRegion[i].uTop <= pRegion->uTop)
                 {
                    SUBT_PRINTF("region overlap 1\n");
                    osd_subt_del_region(i);
                 }
                 else
                 {
                    if(m_SubtRegion[i].uTop <= pRegion->uTop+pRegion->uHeight-1)
                    {
                        SUBT_PRINTF("region overlap 2\n");
                        osd_subt_del_region(i);
                    }
                    else
                    { 
                        //2 region not overlap
                    }
                 }
            }
            else
            {
                //2 region not overlap
            }
        }
    }

    if(m_TotalHeight+pRegion->uHeight >= g_subt_config_par.max_subt_height)
    {
        for(i = 1; i < MAX_REGION_IN_PAGE; i++)
        {
            if(m_UsedRegion_2m[i])
                osd_subt_del_region(i);
        }
    }

    if(m_TotalHeight+pRegion->uHeight >= g_subt_config_par.max_subt_height)
    {
        SUBT_PRINTF("too big subt region\n");
        LEAVE_SUBT_OSD_API();
        return ERR_FAILUE;
    }

    if(m_UsedRegion_2m[region_idx])
    {
        osd_subt_del_region(region_idx);
    }

    //To fix bug reported by E-TEK, subtitle's width is not 16-byte align
    //Michael 2006/3/17
    pRegion->uWidth = ((pRegion->uWidth+0xf)&0xfffffff0); 

     if(RET_SUCCESS != OSDDrv_CreateRegion((HANDLE)osd_dev, region_idx, pRegion, NULL))
     {
        SUBT_PRINTF("%s: create region failed\n", __FUNCTION__);
        LEAVE_SUBT_OSD_API();
        return ERR_FAILUE;
     }
     m_UsedRegion_2m[region_idx] = TRUE;
     m_ShownRegion[region_idx] = TRUE;
                
     m_SubtRegion[region_idx].uLeft = pRegion->uLeft;
     m_SubtRegion[region_idx].uWidth = pRegion->uWidth;
     m_SubtRegion[region_idx].uTop = pRegion->uTop;
     m_SubtRegion[region_idx].uHeight = pRegion->uHeight;
     m_TotalHeight += m_SubtRegion[region_idx].uHeight;
             
     pRegion->uLeft = 0;
	 pRegion->uTop = 0;
	 OSDDrv_RegionFill((HANDLE)osd_dev,region_idx, pRegion, SUBT_TRANSPARENT_COLOR);
     LEAVE_SUBT_OSD_API();
     return SUCCESS;
}

void osd_subt_enter_2m()
{
    int i;
	enum OSDSys  eOSDSys;
	struct OSDPara	tOpenPara;	
	enum TVSystem tvsys;
    //soc_printf("osd_subt_enter_2m\n");
    //ENTER_SUBT_OSD_API();
    while(m_InSubtDecoding == TRUE)
    {
        OS_TaskSleep(1);
    }

    if(g_subt_config_par.speed_up_subt_enable == TRUE)
        OSDDrv_IoCtl((HANDLE)((struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, g_subt_config_par.osd_layer_id)), OSD_IO_SET_BUF_CACHEABLE, TRUE);


    	vpo_ioctl((struct vpo_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DIS), VPO_IO_GET_OUT_MODE, (UINT32)(&tvsys));
	if(tvsys == NTSC||tvsys == PAL_M||tvsys == PAL_60||tvsys == NTSC_443)
		eOSDSys = OSD_NTSC;
	else
		eOSDSys = OSD_PAL;

	tOpenPara.eMode = OSD_256_COLOR;
	tOpenPara.uGAlphaEnable = 0;
	tOpenPara.uGAlpha = 0x0f;
	
	osd_dev = (struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, g_subt_config_par.osd_layer_id);
	
	OSDDrv_Close((HANDLE)osd_dev);
	OSDDrv_Open((HANDLE)osd_dev, &tOpenPara);

	OSDDrv_IoCtl((HANDLE)osd_dev, OSD_IO_SWITH_DATA_TRANSFER_MODE, 1);
		
    m_TotalHeight = 0;
    for(i = 0; i < MAX_REGION_IN_PAGE+1; i++)
    {
        m_UsedRegion_2m[i] = FALSE;
        m_ShownRegion[i] = FALSE;
    }
    g_subt_show_on = TRUE;	
    //LEAVE_SUBT_OSD_API();

    struct OSDRect rect;//cloud, always create a blank region to avoid closing osd in block-link mode to speed up subt
	rect.uLeft= 704;
	rect.uTop= 574;
	rect.uWidth= 16;
	rect.uHeight= 2;
    create_blank_region = TRUE;
    osd_subt_create_region_2m(0, &rect);
    create_blank_region = FALSE;

	OSDDrv_Scale((HANDLE)osd_dev,OSD_VSCALE_TTX_SUBT,(UINT32)(&eOSDSys));
	OSDDrv_ModifyPallette((HANDLE)osd_dev, OSD_TRANSPARENT_COLOR, 0x10, 0x80, 0x80, 0);

	OSDDrv_ShowOnOff((HANDLE)osd_dev, OSDDRV_ON);
}
void osd_subt_leave_2m()
{
    int i;

    while(m_InSubtDecoding == TRUE)
    {
        OS_TaskSleep(1);
    }
    
    if(g_subt_show_on == TRUE)
        g_subt_show_on = FALSE;
    else
        return;//if we don't enter subt osd, we shoule do nothing in leave subt osd.--cloud

#if 0
    osd_subt_del_region(0);//del blank region,cloud
    for(i = 1; i < MAX_REGION_IN_PAGE; i++)
    {
        if(m_UsedRegion_2m[i])
            osd_subt_del_region(i);
    }

    
    
    if(g_subt_config_par.speed_up_subt_enable == TRUE)
        OSDDrv_IoCtl((HANDLE)((struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, g_subt_config_par.osd_layer_id)), OSD_IO_SET_BUF_CACHEABLE, FALSE);
#endif
    osd_dev = (struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD,g_subt_config_par.osd_layer_id);
	OSDDrv_ShowOnOff((HANDLE)osd_dev, OSDDRV_OFF);
    OSDDrv_Close((HANDLE)osd_dev);
    //LEAVE_SUBT_OSD_API();
}
void osd_subt_set_clut_2m(UINT8 entry_id,UINT8 y,UINT8 cb,UINT8 cr,UINT8 t)
{
    ENTER_SUBT_OSD_API();
    if(g_subt_show_on == TRUE)
    {
	    OSDDrv_ModifyPallette((HANDLE)osd_dev, entry_id, y,cb,cr,t);
    }
    LEAVE_SUBT_OSD_API();
}
__ATTRIBUTE_RAM_
void osd_subt_clear_page_2m()
{
	UINT8 i;
	struct OSDRect r1, r2;

    ENTER_SUBT_OSD_API();
    
	if(g_subt_show_on == FALSE)
	{
        LEAVE_SUBT_OSD_API();
		return;
	}
	SUBT_PRINTF("%s\n", __FUNCTION__);
	for(i=1;i<MAX_REGION_IN_PAGE;i++)
	{
        if(m_UsedRegion_2m[i] && m_ShownRegion[i])
        {
            SUBT_PRINTF("%s: show off region(%d).\n", __FUNCTION__, i);
            //OSDDrv_RegionShow((HANDLE)osd_dev,i,0);
            osd_subt_del_region(i);
        }
        else
        {
            SUBT_PRINTF("%s: show NULL region(%d).\n", __FUNCTION__, i);
        }
	}
    LEAVE_SUBT_OSD_API();
}

__ATTRIBUTE_RAM_
INT32 osd_subt_delete_region_2m(UINT8 region_idx)
{
    INT32 ret;
    ENTER_SUBT_OSD_API();
	if(g_subt_show_on == FALSE)
	{
		ret = ERR_FAILUE;
	}
    else
    {
	    SUBT_PRINTF("%s, region_idx = %d\n", __FUNCTION__, region_idx);
	    region_idx++;
        ret = osd_subt_del_region(region_idx);
    }
    LEAVE_SUBT_OSD_API();
    return ret;
}

__ATTRIBUTE_RAM_
INT32 osd_subt_region_show_2m(UINT8 region_idx,UINT8 on)
{
    INT32 ret = ERR_FAILUE;

    ENTER_SUBT_OSD_API();
	if(g_subt_show_on == FALSE)
		ret = ERR_FAILUE;
    else
    {
	    SUBT_PRINTF("%s, region_idx = %d, on = %d\n", __FUNCTION__, region_idx, on);
	    region_idx++;
    
        if(m_UsedRegion_2m[region_idx])
        {
            if(on && m_ShownRegion[region_idx] == FALSE)
            {
                m_ShownRegion[region_idx] = TRUE;
	            ret = (OSDDrv_RegionShow((HANDLE)osd_dev,region_idx,TRUE));    
            }
            else if((!on) && m_ShownRegion[region_idx] == TRUE)
            {
                m_ShownRegion[region_idx] = FALSE;
	            ret = (OSDDrv_RegionShow((HANDLE)osd_dev,region_idx,FALSE));    
            }
        }
        else
        {
            SUBT_PRINTF("%s: show NULL region(%d).\n", __FUNCTION__, region_idx);
            ret = ERR_FAILUE;
        }
    }
    LEAVE_SUBT_OSD_API();
    return ret;
}

__ATTRIBUTE_RAM_
INT32 osd_subt_draw_pixel_2m(UINT8 region_idx,UINT16 x,UINT16 y,UINT8 data)
{
    INT32 ret;

    ENTER_SUBT_OSD_API();
    if(g_subt_show_on == FALSE)
    {
		ret = ERR_FAILUE;
    }
    else
    {
        region_idx++;
	    if(m_UsedRegion_2m[region_idx])
	    {
            if(x > m_SubtRegion[region_idx].uWidth || y > m_SubtRegion[region_idx].uHeight)
            {
                SUBT_PRINTF("%s: out of region(%d), x = %d, y = %d, width = %d, height = %d.\n", \
                    __FUNCTION__, region_idx, x, y, m_SubtRegion[region_idx].uWidth, m_SubtRegion[region_idx].uHeight);
                //ASSERT(0);
                ret = ERR_FAILUE;
            }
            else
            {
#if 0
                ret = (OSDDrv_DrawHorLine((HANDLE)osd_dev,region_idx,(UINT32)x,(UINT32)y,1,(UINT32)data));
#else
                 struct OSDRect r;
	             r.uLeft = x;
	             r.uTop = y;
	             r.uWidth = 1;
	             r.uHeight = 1;
                 OSDDrv_RegionFill((HANDLE)osd_dev,region_idx,&r,data);
                 ret = SUCCESS;
#endif
            }
    
	    }
        else
        {
            SUBT_PRINTF("%s: draw NULL region(%d).\n", __FUNCTION__, region_idx);
            ret =  ERR_FAILUE;
        }
    }
    LEAVE_SUBT_OSD_API();
    return ret;
}
// -- for sdk
//void osd_subt_draw_pixelmap_2m(struct OSDRect rect, UINT8* data)
//{
//}

INT32 osd_subt_get_region_addr_2m(UINT8 region_idx,UINT16 y, UINT32 *addr)
{
    INT32 ret;
    ENTER_SUBT_OSD_API();
    if(g_subt_show_on == FALSE)
        ret = ERR_FAILUE;
    else
	    ret = OSDDrv_GetRegionAddr((HANDLE)osd_dev,region_idx+1,y,addr);
    LEAVE_SUBT_OSD_API();
    return ret;
}

INT32 osd_subt_display_define_2m(struct sdec_display_config *cfg)
{
	return 0;
}
